/******************************************************************************
 * @file  soft_spi.c
 * 
 * @brief  Define soft spi functions
 *
 * @author zhanhongjun
 *
 * @date   2025-10-28
 * 
 * @version  Origin version V1.0.0
 *
 ******************************************************************************/
#include "stm32f10x.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"

#include "soft_spi.h"


/*************************************************************
  * @brief  Soft SPI GPIO and Pins init.
  * @param  None
  * @retval None
  *************************************************************/
static void spi_gpio_init(void)
{
	// Enable GPIO clock
	// RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
    // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE, ENABLE);
    
	// Init SPI GPIOs
	GPIO_InitTypeDef	GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin   = SPI_CS_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;	
	GPIO_Init(SPI_CS_GPIO, &GPIO_InitStructure); 

    GPIO_InitStructure.GPIO_Pin   = SPI_CLK_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;	
	GPIO_Init(SPI_CLK_GPIO, &GPIO_InitStructure); 
    
    GPIO_InitStructure.GPIO_Pin   = SPI_DO_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;	
	GPIO_Init(SPI_DO_GPIO, &GPIO_InitStructure); 
    
    GPIO_InitStructure.GPIO_Pin   = SPI_DI_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;	
	GPIO_Init(SPI_DI_GPIO, &GPIO_InitStructure);
}


void spi_cs_low(void)
{
	GPIO_ResetBits(SPI_CS_GPIO, SPI_CS_PIN);
}


void spi_cs_high(void)
{
	GPIO_SetBits(SPI_CS_GPIO, SPI_CS_PIN);
}


static void spi_clk_low(void)
{
	GPIO_ResetBits(SPI_CLK_GPIO, SPI_CLK_PIN);
}


static void spi_clk_high(void)
{
	GPIO_SetBits(SPI_CLK_GPIO, SPI_CLK_PIN);
}


static void spi_do_low(void)
{
	GPIO_ResetBits(SPI_DO_GPIO, SPI_DO_PIN);
}


static void spi_do_high(void)
{
	GPIO_SetBits(SPI_DO_GPIO, SPI_DO_PIN);
}


static uint8_t spi_di_get_bit(void)
{
    return GPIO_ReadInputDataBit(SPI_DI_GPIO, SPI_DI_PIN);
}



/*************************************************************
  * @brief  Soft SPI GPIO and Pins init.
  * @param  None
  * @retval None
  *************************************************************/
void spi_init(void)
{
	spi_gpio_init();

	/* SPI Mode3(1,1) */
	spi_cs_high();
	spi_clk_high();
	spi_do_high();
}


/*************************************************************
  * @brief  spi read and write a byte data of Mode 3 (1, 1).
  * @param  txData: send data.
  * @retval rxData: receive data.
  *************************************************************/
uint8_t spi_read_write_byte(uint8_t txData)
{
	uint8_t rxData = 0;

	for (uint8_t i = 0; i < 8; i++)
	{
		if (txData & 0x80)	// MSB first
		{
			spi_do_high();
		}
		else
		{
			spi_do_low();
		}
		txData <<= 1;

		spi_clk_low();
	    spi_delay();

		spi_clk_high();
		
		rxData <<= 1;
		rxData |= spi_di_get_bit();
		
		spi_delay();
	}

	return rxData;
}



void spi_delay(void)
{
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
	__nop();
}

/*******************************************************************************
 * EOF (not truncated)
 ******************************************************************************/
